<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>js对象之拷贝</title>
</head>
<body>
  <ul>
    <li>可使用for循环,...展开语法,Object.assign()进行对象浅拷贝</li>
    <li>可使用递归算法或JSON.parse(JSON.stringify())进行对象深拷贝(对象成员包含子对象以及数组，JSON不支持拷贝对象方法)</li>
  </ul>
  <script>
    // 浅拷贝
    const user = { name: 'Miracle', age: 35 }
    function printUser(func, obj, clone, hooks = {}) {
      const { before, after, update } = hooks
      console.log(`*******************${func}*******************`)
      before && before(obj)
      console.log(`before: ${JSON.stringify(obj, null, 2)}`)
      const res = update ? update(clone(obj)) : clone(obj)
      console.log(`clone: ${JSON.stringify(res, null, 2)}`)
      console.log(`after: ${JSON.stringify(obj, null, 2)}`)
      after && after(obj, res)
    }
    function cloneUserByFor() {
      printUser('cloneUserByFor', user, () => {
        const res = {}
        for (const key in user) {
          res[key] = user[key]
        }
        return res
      }, {
        update: res => {
          res.name = 'Miracle He'
          return res
        }
      })
    }
    function cloneUserByExpandSyntax() {
      printUser('cloneUserByExpandSyntax', user, () => ({ ...user, name: 'Miracle He' }))
    }
    function cloneUserByObjectAssign() {
      printUser('cloneUserByObjectAssign', user, () => Object.assign({}, user, { name: 'Miracle He' }))
    }
    function cloneUserByJSON() {
      printUser('cloneUserByJSON', user, () => JSON.parse(JSON.stringify(user)), {
        update: res => {
          res.name = 'Miracle He'
          return res
        }
      })
    }
    // *******************cloneUserByFor*******************
    // before: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    // clone: {
    //   "name": "Miracle He",
    //   "age": 35
    // }
    // after: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    cloneUserByFor()
    // *******************cloneUserByExpandSyntax*******************
    // before: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    // clone: {
    //   "name": "Miracle He",
    //   "age": 35
    // }
    // after: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    cloneUserByExpandSyntax()
    // *******************cloneUserByObjectAssign*******************
    // before: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    // clone: {
    //   "name": "Miracle He",
    //   "age": 35
    // }
    // after: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    cloneUserByObjectAssign()
    // *******************cloneUserByJSON*******************
    // before: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    // clone: {
    //   "name": "Miracle He",
    //   "age": 35
    // }
    // after: {
    //   "name": "Miracle",
    //   "age": 35
    // }
    cloneUserByJSON()
    // 深拷贝
    const userInfo = {
      name: 'Miracle',
      age: 35,
      skills: ['js', 'es', 'ts'],
      git: {
        url: 'https://github.com/miracle-git',
        show() {
          console.log(`visit ${userInfo.name}'s git: ${userInfo.git.url}`)
        }
      }
    }
    function cloneUserByRecursive(obj) {
      const res = obj instanceof Array ? [] : {}
      for (const [key, val] of Object.entries(obj)) {
        res[key] = typeof val === 'object' ? cloneUserByRecursive(val) : val
      }
      return res
    }
    // *******************cloneByRecursive*******************
    // visit Miracle's git: https://github.com/miracle-git
    // before: {
    //   "name": "Miracle",
    //   "age": 35,
    //   "skills": [
    //     "js",
    //     "es",
    //     "ts"
    //   ],
    //   "git": {
    //      "url": "https://github.com/miracle-git"
    //   }
    // }
    // clone: {
    //   "name": "Miracle He",
    //   "age": 35,
    //   "skills": [
    //     "js",
    //     "es",
    //     "ts",
    //     "css"
    //   ],
    //   "git": {
    //     "url": "https://github.com/miracle-git/fts"
    //   }
    // }
    // after: {
    //   "name": "Miracle",
    //   "age": 35,
    //   "skills": [
    //     "js",
    //     "es",
    //     "ts"
    //   ],
    //   "git": {
    //     "url": "https://github.com/miracle-git"
    //   }
    // }
    // visit Miracle He's git: https://github.com/miracle-git, learning js,es,ts
    // visit Miracle's git: https://github.com/miracle-git
    printUser('cloneUserByRecursive', userInfo, cloneUserByRecursive, {
      before: (obj) => {
        obj.git.show()
      },
      update: (res) => {
        res.name = 'Miracle He'
        res.git.url = 'https://github.com/miracle-git/fts'
        res.skills.push('css')
        res.git.show = function () {
          console.log(`visit ${res.name}'s git: ${res.git.url}, learning ${res.skills}`)
        }
        return res
      },
      after: (obj, res) => {
        res.git.show()
        obj.git.show()
      }
    })
  </script>
</body>
</html>
